#include<mpi.h>
#include<iostream>
#include<fstream>
#include<time.h>
#include"Raytracer.h"
#include"libbmp/EasyBMP.h"

void wait()
{
	std::cin.sync();
	std::cin.get();
}

int main(int argc, char** argv)
{
	//loading config
//	char path[256];
	char primeName[256];
//	std::cout<<"Enter path to scene file : ";
//	std::cin>>path;
	std::ifstream input("test2.txt");
	if(input.fail())
	{
		std::cout << "No configuration found";
		wait();
		return 0;
	}
		
	//timer init
	const time_t t1 = time(NULL);
	time_t t2 = time(NULL);

	//creating enviroment
	XYZ eye;
	XYZ planePos;
	XYZ ox, oy;
	Color bgColor;
	Color globLight;
	double planeSizeX, planeSizeY;
	int planeResX, planeResY;

	input>>eye.x>>eye.y>>eye.z;
	input>>planePos.x>>planePos.y>>planePos.z;
	input>>ox.x>>ox.y>>ox.z;
	input>>oy.x>>oy.y>>oy.z;
	input>>planeSizeX>>planeSizeY>>planeResX>>planeResY;
	input>>bgColor.r>>bgColor.g>>bgColor.b;
	input>>globLight.r>>globLight.g>>globLight.b;

	Raytracer rt(eye, planePos, ox, oy, planeSizeX, planeSizeY, planeResX, planeResY);
	rt.SetBackground(bgColor);
	rt.SetGlobalLight(globLight);

	int spheresAm;
	input>>spheresAm;

	for(int i = 0; i<spheresAm; i++){
		input>>primeName;
		if (!strcmp(primeName,"SPHERE"))
		{
			Sphere * sp = new Sphere();
			sp->loadSphere(&input);
			rt.AddPrimitive(sp);
		}
		if (!strcmp(primeName,"POLYGON"))
		{
			Polygon * pg = new Polygon();
			pg->loadPolygon(&input);
			rt.AddPrimitive(pg);
		}
	}

	int lightsAm;
	input>>lightsAm;

	for(int i = 0; i<lightsAm; i++){
		Light l;
		input>>l.pos.x>>l.pos.y>>l.pos.z>>l.col.r>>l.col.g>>l.col.b;
		rt.AddLight(l);
	}

	int rank, size;
	MPI_Init(&argc, &argv);
	MPI_Status status;
	MPI_Comm_rank(MPI_COMM_WORLD, &rank);
	MPI_Comm_size(MPI_COMM_WORLD, &size);

	int percentsLast = 0;
	int percentsDone = 0;

	int from = planeResX/(size-1) * (rank-1);
	int to = planeResX/(size-1) * (rank);
	int s = planeResX/(size-1);
	Pixel *pix = new Pixel[s*planeResY];
	if (rank != 0)
	{
	int k = 0;
	std::cerr << "From = " << from << " to = " << to << "\n";
		for(int i = from; i<to; i++){
			for(int j = 0; j<planeResY; j++){
				Color c = rt.getPixelColor(i, j);
				pix[k*planeResY + j].x = i;
				pix[k*planeResY + j].y = j;
				pix[k*planeResY + j].r = c.r;
				pix[k*planeResY + j].g = c.g;
				pix[k*planeResY + j].b = c.b;
				percentsDone = int(float(i*planeResY + j)/float(planeResX*planeResY) * 100);
				double tim =  0;
				t2 = time(NULL);
				tim = difftime(t2, t1);
				if(percentsDone != percentsLast){
					percentsLast = percentsDone;
					std::cout<<"\r"<<percentsDone<<"% done. It took " << float(clock())/CLOCKS_PER_SEC/*tim*/ << " seconds.";
				}
			}
		k++;
		}
		MPI_Ssend(pix, sizeof(Pixel)*s*planeResY, MPI_BYTE, 0, 123, MPI_COMM_WORLD);
	}
	else
	{
	BMP image;
	image.SetSize(planeResX, planeResY);
	for(int i = 0; i < size-1; i++)
		{
			MPI_Recv(pix, sizeof(Pixel)*s*planeResY, MPI_BYTE, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
			for (int j = 0; j < s*planeResY; j++)
			{
				image(pix[j].x, pix[j].y)->Red = pix[j].r;
				image(pix[j].x, pix[j].y)->Green = pix[j].g;
				image(pix[j].x, pix[j].y)->Blue = pix[j].b;
			}
		}
	image.WriteToFile("out.bmp");
	std::cout<<"\rRaytracing done! "<< "It took " << float(clock())/CLOCKS_PER_SEC << " seconds. " << "Press enter to continue.\n";
	}

	/*if (rank == 0)
	{
		//std::cout<<"\rSaving image...";
		//image.WriteToFile("out.bmp");
	}*/

	MPI_Finalize();
	//if (rank == 0) wait();
}
